﻿using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace RSAID
{
    [Serializable]
    [SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true, MaxByteSize = 8000, Name = "RSAID", IsFixedLength = false)]
    public class SqlRSAID : INullable, IBinarySerialize, IComparable
    {
        private ValidatedRSAID _id;             // should be immutable, but UDT deserialization requires state mutation :(

        #region ctor

        public SqlRSAID()
        {
            _id = new ValidatedRSAID(null);
        }

        public SqlRSAID(string idNumber)
        {
            _id = new ValidatedRSAID(idNumber);
        }

        #endregion

        #region UDT properties

        public bool IsValid
        {
            get
            {
                return _id.IsValid;
            }
        }

        public SqlDateTime DateOfBirth
        {
            get
            {
                return _id.DateOfBirth.HasValue ? 
                       _id.DateOfBirth.Value : 
                       SqlDateTime.Null;
            }
        }

        public SqlString Gender
        {
            get
            {
                return _id.Gender.HasValue
                           ? (_id.Gender.Value == RSAID.Gender.Female ? "F" : "M")
                           : SqlString.Null;
            }
        }

        public SqlBoolean IsCitizen
        {
            get
            {
                return _id.IsCitizen.HasValue ? _id.IsCitizen.Value : SqlBoolean.Null;
            }
        }

        #endregion

        #region INullable

        private static readonly SqlRSAID _null = new SqlRSAID();

        public static SqlRSAID Null { get { return _null; } }

        public bool IsNull
        {
            get
            {
                return string.IsNullOrEmpty(_id.IDNumber);
            }
        }

        #endregion

        #region IBinarySerialize

        public void Read(System.IO.BinaryReader r)
        {
            var notNull = r.ReadBoolean();
            if (notNull)
                _id = new ValidatedRSAID(r.ReadString());
        }

        public void Write(System.IO.BinaryWriter w)
        {
            var notNull = !IsNull;
            w.Write(notNull);
            if (notNull)
                w.Write(_id.IDNumber);
        }

        #endregion

        public override string ToString()
        {
            return _id.IDNumber;
        }

        public static SqlRSAID Parse(SqlString idNumber)
        {
            return idNumber.IsNull ?
                    Null :
                    new SqlRSAID(idNumber.Value);
        }

        public int CompareTo(object obj)
        {
            var other = obj as SqlRSAID;

            if (other == null)
                return 1;

            return string.Compare(_id.IDNumber, other._id.IDNumber);
        }
    }
}